﻿using System;
using System.Collections.Generic;
using System.Text;

namespace XendApp
{
    public class Client
    {
        private string u = string.Empty;
        private string p = string.Empty;
        private System.Net.WebProxy pr = null;

        /// <summary>
        /// Create a new Client object
        /// </summary>
        /// <param name="username">Username or email at xendapp.com</param>
        /// <param name="password">Password at xendapp.com</param>
        /// <param name="proxy">Optional sending through proxy. Specify null if not used.</param>
        public Client(string username, string password, System.Net.WebProxy proxy)
        {
            u = username;
            p = password;
        }

        /// <summary>
        /// Validates a username and password - for testing
        /// </summary>
        /// <returns></returns>
        public ValidationResult ValidateUser()
        {
            com.xendapp.userservice.UserValidationResult result = com.xendapp.userservice.UserValidationResult.Undefined;
            ValidationResult vr = new ValidationResult();
            
            try
            {
                com.xendapp.userservice.UserService us = new com.xendapp.userservice.UserService();
                us.Proxy = pr;
                                
                bool userValidationResultSpecified;
                us.ValidateUser(u, p, out result, out userValidationResultSpecified);

                switch (result)
                {
                    case com.xendapp.userservice.UserValidationResult.Failed:
                        vr.ValidationResultType = ValidationResult.ValidationResultT.Failed;
                        break;
                    case com.xendapp.userservice.UserValidationResult.NotApproved:
                        vr.ValidationResultType = ValidationResult.ValidationResultT.NotApproved;
                        break;
                    case com.xendapp.userservice.UserValidationResult.Success:
                        vr.ValidationResultType = ValidationResult.ValidationResultT.Success;
                        break;
                    case com.xendapp.userservice.UserValidationResult.Undefined:
                        vr.ValidationResultType = ValidationResult.ValidationResultT.Undefined;
                        break;
                }
            }
            catch (Exception ex)
            {
                vr.ErrorString = ex.Message;
                vr.ValidationResultType = ValidationResult.ValidationResultT.Error;
            }

            return vr;
        }

        public List<Provider> GetCreatedProviderChannelByUser()
        {
            List<Provider> providers = new List<Provider>();
            com.xendapp.providerservice.ProviderService ps = new com.xendapp.providerservice.ProviderService();
            ps.Proxy = pr;
           
             // the provider(s) and channel(s) that user has created
            foreach (com.xendapp.providerservice.P prov in ps.GetUserProvidersWithChannels(u, p))
            {
                Provider provider = new Provider();
                provider.Id = new Guid(prov.I);
                provider.Name = prov.N;
                if (prov.CS != null)
                {
                    foreach (com.xendapp.providerservice.C c in prov.CS)
                    {
                        Channel channel = new Channel();
                        channel.Id = new Guid(c.I);
                        channel.Name = c.N;
                        provider.Channels.Add(channel);
                    }
                }

                providers.Add(provider);
            }

            return providers;
             
        }

        /// <summary>
        /// Returns a lis of Providers and their Channels
        /// </summary>
        /// <returns></returns>
        public List<Provider> GetSubcribedProviderChannelByUser()
        {
            List<Provider> providers = new List<Provider>();

            com.xendapp.channelservice.ChannelService cs = new com.xendapp.channelservice.ChannelService();
            cs.Proxy = pr;

            // the provider(s) and channel(s) that user subscribe to
            foreach (com.xendapp.channelservice.PH providerHeader in cs.GetUserChannels(u, p).PHS)
            {
                Provider provider = new Provider();
                provider.Id = new Guid(providerHeader.I);
                provider.Name = providerHeader.N;

                if (providerHeader.CHS != null)
                {
                    foreach (com.xendapp.channelservice.CH channelHeader in providerHeader.CHS)
                    {
                        Channel channel = new Channel();
                        channel.Id = new Guid(channelHeader.I);
                        channel.Name = channelHeader.N;
                        provider.Channels.Add(channel);
                    }
                }

                providers.Add(provider);
            }

            return providers;
        }

        public SendResult Send(Message m)
        {
            SendResult r = new SendResult();

            try
            {
                com.xendapp.messageservice.MessageService ms = new com.xendapp.messageservice.MessageService();
                com.xendapp.messageservice.MTS xendappmessage = new com.xendapp.messageservice.MTS();
                ms.Proxy = pr;

                // subject
                xendappmessage.S = Client.ToBase64(m.Subject);

                // body
                xendappmessage.B = Client.ToBase64(m.Body);

                // channel id
                xendappmessage.CI = m.ChannelId.ToString();

                // message expiration
                if (m.ExpireDays == 0)
                {
                    xendappmessage.ESpecified = false;
                } else
                {
                    xendappmessage.ESpecified = true;
                    xendappmessage.E = Client.ToUnixTimeStamp(DateTime.Now.AddDays(m.ExpireDays));
                }

                // encryption
                xendappmessage.EC = m.Encrypted;
                xendappmessage.ECSpecified = true;

                // content type
                xendappmessage.CTISpecified = true;
                switch (m.ContentType)
                {
                    case Message.ContentT.PlainText:
                        xendappmessage.CTI = (int)m.ContentType;
                        break;
                    case Message.ContentT.HTML:
                        xendappmessage.CTI = (int)m.ContentType;
                        break;
                    default:
                        throw new Exception("Unknown ContentType. Upgrade API.");
                }
                com.xendapp.messageservice.SMR smr = ms.SendMessage(u, p, xendappmessage);
                r.Success = smr.S;
                if (r.Success)
                {
                    r.Id = new Guid(smr.MI); 
                } else
                {
                    r.ErrorMessage = smr.ES;
                }

                return r;
            }
            catch (Exception ex)
            {
                r.ErrorMessage = ex.ToString();
            }
            
            return r;
        }

        #region "Base64 encoding"
        /// <summary>
        /// To Base64.
        /// </summary>
        public static string ToBase64(string source)
        {
            if (String.IsNullOrEmpty(source))
            {
                return String.Empty;
            }
            return Convert.ToBase64String(Encoding.UTF8.GetBytes(source));
        }

        /// <summary>
        /// From Base64.
        /// </summary>
        public static string FromBase64(string source)
        {
            if (String.IsNullOrEmpty(source))
            {
                return String.Empty;
            }
            return Encoding.UTF8.GetString(Convert.FromBase64String(source));
        }
        #endregion
        
        #region DateTime converters
        private static readonly DateTime baseDate = new DateTime(1970, 1, 1, 0, 0, 0);
        public static long ToUnixTimeStamp(DateTime dateTime)
        {
            TimeSpan timeSpan = dateTime - baseDate;
            return Convert.ToInt64(timeSpan.TotalSeconds);
        }

        public static DateTime FromUnixTimeStamp(long timestamp)
        {
            return baseDate.AddSeconds(timestamp);
        }

        public static DateTime AdjustServerDateToUtc(DateTime dateTime)
        {
            return dateTime.ToUniversalTime();
        }
        #endregion
    }
}
